package com.hzw.saas.service.hpc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.hpc.*;
import com.hzw.saas.api.hpc.bo.*;
import com.hzw.saas.api.hpc.enums.HpcAccountPoolStatus;
import com.hzw.saas.api.hpc.enums.HpcAccountStatus;
import com.hzw.saas.api.hpc.enums.HpcAccountUserType;
import com.hzw.saas.api.hpc.enums.HpcProviderType;
import com.hzw.saas.api.hpc.query.*;
import com.hzw.saas.api.user.ICustomerService;
import com.hzw.saas.api.user.IUserAccountService;
import com.hzw.saas.api.user.bo.CustomerBO;
import com.hzw.saas.common.config.annotation.RedisProcessLock;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.util.Arith;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.service.hpc.event.HpcAccountAllotEvent;
import com.hzw.saas.service.hpc.event.HpcAccountUnAllotEvent;
import com.hzw.saas.service.hpc.exception.PullHpcDetailsException;
import com.hzw.saas.service.hpc.mapper.*;
import com.hzw.saas.service.hpc.model.HpcAccountRecord;
import com.hzw.saas.service.hpc.model.HpcAccountUser;
import com.hzw.saas.service.hpc.service.IHpcAccountSlurmService;
import com.hzw.saas.service.hpc.service.bo.SlurmAccountBO;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.hzw.saas.api.hpc.enums.HpcAccountStatus.*;

/**
 * <p>
 * 用户超算中心帐号表 服务实现类
 * </p>
 *
 * @author zzl
 * @since 2021-02-03
 */
@Slf4j
@Service("hpcAccountUserServiceImpl")
@RequiredArgsConstructor
public class HpcAccountUserServiceImpl extends ServiceImpl<HpcAccountUserMapper, HpcAccountUser> implements IHpcAccountUserService, IService<HpcAccountUser> {
    private final static String CACHE_NAME = "HPC_USER";
    private final static int SUB = HpcAccountUserType.SUB.value(); //副帐号
    private final static int MAIN = HpcAccountUserType.MAIN.value(); //主账号

    @Resource(name = "hpcAccountIncreaseImpl")
    private IHpcAccountIncreaseService hpcAccountIncreaseService;
    @Resource(name = "hpcAccountRecordServiceImpl")
    private IHpcAccountRecordService hpcAccountRecordService;
    @Resource(name = "hpcAccountProviderServiceImpl")
    private IHpcAccountProviderService providerService;
    @Resource(name = "hpcAccountServiceImpl")
    private IHpcAccountService hpcAccountService;
    @Resource(name = "userAccountServiceImpl")
    private IUserAccountService userAccountService;
    @Resource(name = "customerServiceImpl")
    private ICustomerService customerService;
    @Resource(name = "hpcAccountUserServiceImpl")
    private IHpcAccountUserService self;

    @Resource(name = "sshHpcFetchServiceImpl")
    private IHpcFetchService hpcFetchService;
    private final ApplicationEventPublisher publisher;
    private final IHpcAccountSlurmService slurmService;
    private final HpcAccountUserMapper hpcAccountUserMapper;
    private final HpcBalanceOrderMapper hpcBalanceOrderMapper;
    private final HpcAccountDetailMapper hpcAccountDetailMapper;
    private final HpcAccountRecordMapper hpcAccountRecordMapper;
    private final HpcAccountIncreaseMapper hpcAccountIncreaseMapper;
    private final HpcAccountAmountDailyMapper hpcAccountAmountDailyMapper;

    @Override
    @Transactional
    public void initHpcUserData(String hpcAccountUserId) {
        HpcAccountRecordBo hpcAccountRecordBo = hpcAccountUserMapper.getHistoryHpcAccountRecordByHpcUserAccountId(hpcAccountUserId);
        if (Objects.isNull(hpcAccountRecordBo)) {
            log.warn("分配的hpc用户不存在: {}", hpcAccountUserId);
            return;
        }
        // 将同步时间设置很久之前
        hpcAccountRecordBo.setSyncTime(DateUtil.parseDate("2000-01-01"));
        // 清空数据
        clearHpcUserData(hpcAccountRecordBo);
        // 重新拉HPC明细数据
        try {
            hpcFetchService.fetchHpcDetails(hpcAccountRecordBo);
        } catch (PullHpcDetailsException ignore) {
            //~ignore
        };
        // 更新HPC账号余额
        hpcFetchService.updateHpcAccountBalance(hpcAccountRecordBo);
        // 生成每日余额数据
        Date startTime = hpcAccountRecordBo.getCreateTime(); // HPC创建时间
        Date expireTime = hpcAccountRecordBo.getExpireTime();
        Date endTime = DateUtil.compare(expireTime, new Date()) >= 0 ? DateUtil.offsetDay(new Date(), -1) : expireTime;
        for(int i = 0; i <= DateUtil.between(startTime, endTime, DateUnit.DAY); i ++) {
            DateTime curTime = DateUtil.offsetDay(startTime, i);
            hpcAccountRecordService.recordHpcBalanceByDate(hpcAccountRecordBo.getPid(), curTime);
        }
        // 生成增值数据
        hpcAccountIncreaseService.powerIncrease(hpcAccountRecordBo);
    }

    /**
     * 清空数据
     */
    private void clearHpcUserData(HpcAccountRecordBo hpcAccountRecordBo) {
        // 清空历史数据
        String hpcAccountRecordId = hpcAccountRecordBo.getPid();
        // 清空HPC明细数据
        hpcAccountDetailMapper.deleteHpcDetailFromXmlByHpcRecordId(hpcAccountRecordId);
        // 清空增值数据
        hpcAccountIncreaseMapper.deleteHpcIncreaseFromXmlByHpcRecordId(hpcAccountRecordId);
        // 清空每日余额数据
        hpcAccountAmountDailyMapper.deleteHpcAccountAmountDailyFromXmlByHpcRecordId(hpcAccountRecordId);
        // 清空HPC充值记录
        hpcBalanceOrderMapper.deleteHpcAccountAmountDailyFromXmlByHpcRecordId(hpcAccountRecordId);
    }

    @Override
//    @Cacheable(cacheNames = {CACHE_NAME}, key = "#p0")
    public HpcAccountUserBo getWithRecord(String pid) {
        if (StringUtils.isBlank(pid)) {
            return null;
        }
        HpcAccountUser accountUser = this.getById(pid);
        HpcAccountUserBo hpcAccountUserBo = MapperUtil.nf().map(accountUser, HpcAccountUserBo.class);

        if (Objects.nonNull(hpcAccountUserBo)) {
            hpcAccountUserEnhancer(hpcAccountUserBo);
        }

        return hpcAccountUserBo;
    }

    @Override
    public HpcAccountUserBo get(String accountUserId) {
        HpcAccountUser accountUser = this.getById(accountUserId);
        if(Objects.isNull(accountUser)) {
            return null;
        }
        return MapperUtil.nf().map(accountUser, HpcAccountUserBo.class);
    }

    @Override
    public HpcAccountUserBo get(String userId, String hpcAccountId) {
        List<HpcAccountRecord> hpcAccountRecords = hpcAccountRecordMapper.selectList(Wrappers.<HpcAccountRecord>lambdaQuery()
            .select(HpcAccountRecord::getPid)
            .eq(HpcAccountRecord::getUserId, userId).eq(HpcAccountRecord::getHpcAccountId, hpcAccountId)
            .orderByDesc(HpcAccountRecord::getExpireTime));
        if(CollectionUtil.isEmpty(hpcAccountRecords)) {
            return null;
        }
        HpcAccountRecord hpcAccountRecord = hpcAccountRecords.get(0);
        return this.getMainUserByRecordId(hpcAccountRecord.getPid());
    }

    @Override
    public HpcAccountUserBo getMainUserByRecordId(String accountRecordId) {
        if(StringUtil.isBlank(accountRecordId)) return null;
        List<HpcAccountUser> hpcAccountUsers = list(Wrappers.<HpcAccountUser>lambdaQuery().eq(HpcAccountUser::getHpcAccountRecordId, accountRecordId).eq(HpcAccountUser::getIsMain, MAIN));
        return CollectionUtils.isEmpty(hpcAccountUsers) ? null : MapperUtil.nf().map(hpcAccountUsers.get(0), HpcAccountUserBo.class);
    }

    private void hpcAccountUserEnhancer(HpcAccountUserBo hpcAccountUserBo) {
        hpcAccountUserEnhancer(Collections.singletonList(hpcAccountUserBo));
    }

    private void hpcAccountUserEnhancer(List<HpcAccountUserBo> hpcAccountUserBos) {
        if (CollectionUtils.isEmpty(hpcAccountUserBos)) return;

        hpcAccountUserBos.forEach(hpcAccountUserBo -> {
            String hpcAccountRecordId = hpcAccountUserBo.getHpcAccountRecordId();
            HpcAccountRecordBo hpcAccountRecordBo = hpcAccountRecordService.get(hpcAccountRecordId);

            if (Objects.nonNull(hpcAccountRecordBo)) {
                hpcAccountUserBo.setCoreTimeBalance(hpcAccountRecordBo.getCoreTimeBalance());
                hpcAccountUserBo.setCoreTimeBalanceTotal(hpcAccountRecordBo.getCoreTimeBalanceTotal());
                hpcAccountUserBo.setExpireTime(hpcAccountRecordBo.getExpireTime());
                hpcAccountUserBo.setHpcAccountSnapshot(hpcAccountRecordBo.getHpcAccountSnapshot());
                hpcAccountUserBo.setHpcAccountId(hpcAccountRecordBo.getHpcAccountId());
            }

            if (hpcAccountUserBo.getIsMain() == MAIN) {
                List<HpcAccountUser> accountUsers = this.list(Wrappers.<HpcAccountUser>lambdaQuery()
                    .eq(HpcAccountUser::getHpcAccountRecordId, hpcAccountRecordId)
                    .eq(HpcAccountUser::getIsMain, SUB));
                // 过滤已过期的子账号
                accountUsers = accountUsers.stream().filter((hpcAccountUser -> DateUtil.compare(hpcAccountUser.getSubExpireTime(), DateUtil.date()) > 0)).collect(Collectors.toList());

                hpcAccountUserBo.setAccountSubList(MapperUtil.nf().mapAsList(accountUsers, HpcAccountUserBo.class));
            }
        });
    }

    @Override
    public List<HpcAccountUserBo> getList(String userId) {
        List<HpcAccountUser> hpcAccountUsers = this.list(Wrappers.<HpcAccountUser>lambdaQuery().eq(HpcAccountUser::getUserId, userId));

        List<HpcAccountUserBo> hpcAccountUserBos = MapperUtil.nf().mapAsList(hpcAccountUsers, HpcAccountUserBo.class);
        hpcAccountUserEnhancer(hpcAccountUserBos);

        return hpcAccountUserBos;
    }

    @Override
    public List<CustomerBO> listMainSharedCustomers(String userId) {
        return hpcAccountUserMapper.listMainSharedCustomers(userId);
    }

    @Override
    public IPage<HpcAccountUserBo> getUsableListByUserIdPage(PageParam pageParam, String userId, Integer isMain, Boolean isExpire) {
        return hpcAccountUserMapper.getUsableListByPageAndExpireTime(pageParam.convert(), userId, DateUtil.date(), isMain, isExpire);
    }

    @Override
    public List<HpcAccountUserBo> getUsableHpcAccountUserList(List<String> hpcAccountUserIds) {
        if(CollectionUtils.isEmpty(hpcAccountUserIds)) {
            return new ArrayList<>();
        }
        return hpcAccountUserMapper.getUsableHpcAccountUserList(hpcAccountUserIds, DateUtil.date());
    }


    @Override
    public double sumHpcAccountBalance(String userId) {
        if (StringUtils.isBlank(userId)) {
            return 0d;
        }
        List<HpcAccountUser> hpcAccountUsers = this.list(Wrappers.<HpcAccountUser>lambdaQuery().eq(HpcAccountUser::getUserId, userId));

        double sum = 0d;
        for (HpcAccountUser hpcAccountUser : hpcAccountUsers) {
            String hpcAccountRecordId = hpcAccountUser.getHpcAccountRecordId();
            HpcAccountRecordBo hpcAccountRecordBo = hpcAccountRecordService.get(hpcAccountRecordId);
            sum = Arith.add(hpcAccountRecordBo.getCoreTimeBalance(), sum);
        }

        return sum;
    }

    @Override
    @Transactional
    @RedisProcessLock(lockName = "BoundHpcAccount", key = "#mainHpcAccountQuery.hpcAccountId")
    public HpcAccountUserBo addMainAccountUser(MainHpcAccountQuery mainHpcAccountQuery) {
        if (mainHpcAccountQuery == null) {
            return null;
        }

        if(mainHpcAccountQuery.isIncludeCurDay()) {
            // 设置当天最后一小时
            mainHpcAccountQuery.setExpireTime(DateUtil.offsetSecond(DateUtil.endOfDay(mainHpcAccountQuery.getExpireTime()), -1));
        }

        String userId = mainHpcAccountQuery.getUserId();
        AssertUtil.assertThrow("设置用户HPC失败，该用户不存在", !userAccountService.existAccount(userId));

        HpcAccountUserBo accountUserBo = MapperUtil.nf().map(mainHpcAccountQuery, HpcAccountUserBo.class);
        // 生成主键
        accountUserBo.setPid(String.valueOf(SnowFlakeUtil.nextId()));
        // 设置账号状态
        accountUserBo.setStatus(mainHpcAccountQuery.getAccountUserStatus());
        // 设置为主账号
        accountUserBo.setIsMain(MAIN);

        HpcAccountRecordQuery hpcAccountRecordQuery = MapperUtil.nf().map(mainHpcAccountQuery, HpcAccountRecordQuery.class);
        hpcAccountRecordQuery.setSlurmAccount(mainHpcAccountQuery.getSlurmAccount());
        HpcAccountRecordBo hpcAccountRecordBo = hpcAccountRecordService.add(hpcAccountRecordQuery);
        accountUserBo.setHpcAccountRecordId(hpcAccountRecordBo.getPid());

        HpcAccountUser hpcAccountUser = MapperUtil.nf().map(accountUserBo, HpcAccountUser.class);
        this.save(hpcAccountUser);

        return accountUserBo;
    }

    @Override
    public int countSub(String hpcAccountUserId) {
        HpcAccountUserBo hpcAccountUserBo = self.get(hpcAccountUserId);
        String hpcAccountRecordId = hpcAccountUserBo.getHpcAccountRecordId();
        return this.lambdaQuery().eq(HpcAccountUser::getHpcAccountRecordId, hpcAccountRecordId).eq(HpcAccountUser::getIsMain, HpcAccountUserType.SUB.value()).count();
    }

    @Override
    @Transactional
    public void addSubAccountUser(List<SubHpcAccountQuery> subHpcAccountQueries) {
        // TODO 获取用户能够分享HPC账号的最大数量，并做限制

        if (CollectionUtils.isEmpty(subHpcAccountQueries)) {
            return;
        }
        List<HpcAccountUser> needSaveHpcAccountUserList = new ArrayList<>();

        subHpcAccountQueries.forEach(subHpcAccountQuery -> {
            String userId = subHpcAccountQuery.getUserId();
            AssertUtil.assertThrow("设置用户HPC共享账号失败，该用户不存在", !userAccountService.existAccount(userId));

            // 获取主账号信息
            String hpcAccountUserId = subHpcAccountQuery.getHpcAccountUserId();
            HpcAccountUserBo mainAccountUserBo = self.getWithRecord(hpcAccountUserId);
            AssertUtil.assertThrow("设置用户HPC共享账号失败，该HPC账号不存在", Objects.isNull(mainAccountUserBo));
            AssertUtil.assertThrow("设置用户HPC共享账号失败，该HPC账号不能分享",mainAccountUserBo.getCanShare() != 1);
            AssertUtil.assertThrow("设置用户HPC共享账号失败，该HPC账号不是主账号", !Objects.equals(mainAccountUserBo.getIsMain(), MAIN));
            AssertUtil.assertThrow("设置用户HPC共享账号失败，该用户是HPC账号的主账号", Objects.equals(mainAccountUserBo.getUserId(), userId));
            AssertUtil.assertThrow("设置用户HPC共享账号失败，该用户是HPC账号的子账号",
                this.count(Wrappers.<HpcAccountUser>lambdaQuery()
                    .eq(HpcAccountUser::getUserId, userId)
                    .eq(HpcAccountUser::getHpcAccountRecordId, mainAccountUserBo.getHpcAccountRecordId())
                    .ne(HpcAccountUser::getIsMain, MAIN)
                    .gt(HpcAccountUser::getSubExpireTime, DateUtil.date())) != 0);
            // 构造共享帐号
            HpcAccountUser hpcAccountUser = new HpcAccountUser();
            hpcAccountUser.setPid(String.valueOf(SnowFlakeUtil.nextId()));
            hpcAccountUser.setIsMain(SUB);
            hpcAccountUser.setIsInfinite(mainAccountUserBo.getIsInfinite()); // 继承主账户的属性
            hpcAccountUser.setCanShare(0); // 不能分享
            hpcAccountUser.setUserId(userId);
            hpcAccountUser.setStatus(subHpcAccountQuery.getSubHpcAccountStatus() == null ?
                NORMAL.value() :
                subHpcAccountQuery.getSubHpcAccountStatus());
            hpcAccountUser.setHpcAccountRecordId(mainAccountUserBo.getHpcAccountRecordId());
            // 共享时间和主账号保持一致
            hpcAccountUser.setSubExpireTime(mainAccountUserBo.getExpireTime());
//            hpcAccountUser.setSubExpireTime(DateUtil.compare(subHpcAccountQuery.getExpireTime(), mainAccountUserBo.getExpireTime()) > 0 ? mainAccountUserBo.getExpireTime() : subHpcAccountQuery.getExpireTime());
            needSaveHpcAccountUserList.add(hpcAccountUser);
        });

        // 批量插入
        if (CollectionUtils.isNotEmpty(needSaveHpcAccountUserList)) {
            this.saveBatch(needSaveHpcAccountUserList);
        }
    }

    @Override
    @RedisProcessLock(lockName = "CancelShareHpcAccount", key = "#hpcAccountUserId + ':' + #userId")
    public void cancelShareHpcAccount(String hpcAccountUserId, String userId) {
        HpcAccountUserBo accountUserBo = self.get(hpcAccountUserId);
        AssertUtil.assertThrow("删除共享账号失败，数据异常，请重试", Objects.isNull(accountUserBo));
        // 查询没有过期的共享账户
        List<HpcAccountUser> list = this.list(Wrappers.<HpcAccountUser>lambdaQuery()
            .eq(HpcAccountUser::getHpcAccountRecordId, accountUserBo.getHpcAccountRecordId())
            .eq(HpcAccountUser::getUserId, userId)
            .eq(HpcAccountUser::getIsMain, SUB));
        AssertUtil.assertThrow("删除共享账号失败，该共享账号不存在", CollectionUtil.isEmpty(list));
        // 删除
        self.delete(list.get(0).getPid());
    }

    @Override
    @Transactional
    @CacheEvict(cacheNames = {CACHE_NAME}, key = "#p0.hpcAccountUserId", condition = "#p0 != null and #p0.hpcAccountUserId != null")
    public boolean frozenHpcAccount(HpcAccountUserFrozenQuery accountUserUpdateQuery) {
        // 更新HpcUser状态
        if (accountUserUpdateQuery == null || StringUtil.isBlank(accountUserUpdateQuery.getHpcAccountUserId()))
            return false;
        String hpcAccountUserId = accountUserUpdateQuery.getHpcAccountUserId();
        HpcAccountUserBo accountUserBo = self.getWithRecord(hpcAccountUserId);
        if (Objects.isNull(accountUserBo)) return false;

        Integer isMain = accountUserBo.getIsMain();
        if (isMain == MAIN) {
            String hpcAccountRecordId = accountUserBo.getHpcAccountRecordId();
            HpcAccountStatus hpcAccountStatus = accountUserUpdateQuery.getHpcAccountStatus();
            // 主账号冻结
            List<HpcAccountUser> hpcAccountUsers = this.list(Wrappers.<HpcAccountUser>lambdaQuery().eq(HpcAccountUser::getHpcAccountRecordId, hpcAccountRecordId));
            hpcAccountUsers.forEach(hpcAccountUser -> {
                HpcAccountUser accountUser = new HpcAccountUser();
                accountUser.setPid(hpcAccountUser.getPid());
                accountUser.setStatus(hpcAccountStatus.value());
                this.updateById(accountUser);
            });
            // 提交冻结获或解冻事件
            HpcAccountRecordBo hpcAccountRecordBo = hpcAccountRecordService.get(hpcAccountRecordId);
            HpcAccountBo hpcAccountBo = hpcAccountService.getById(hpcAccountRecordBo.getHpcAccountId());
            switch (hpcAccountStatus) {
                case NORMAL:
                    publisher.publishEvent(new HpcAccountAllotEvent(hpcAccountBo));
                    break;
                case DISABLED:
                    publisher.publishEvent(new HpcAccountUnAllotEvent(hpcAccountBo));
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + hpcAccountStatus);
            }
            return true;
        } else {
            // 副帐号冻结
            HpcAccountUser hpcAccountUser = new HpcAccountUser();
            hpcAccountUser.setPid(hpcAccountUserId);
            hpcAccountUser.setStatus(accountUserUpdateQuery.getHpcAccountStatus().value());
            return this.updateById(hpcAccountUser);
        }
    }

    @Override
    @CacheEvict(cacheNames = {CACHE_NAME}, key = "#p0.pid")
    public boolean update(HpcAccountUserBo hpcAccountUserBo) {
        if(Objects.isNull(hpcAccountUserBo)) return false;
        if(StringUtil.isBlank(hpcAccountUserBo.getPid())) return false;
        return this.updateById(MapperUtil.nf().map(hpcAccountUserBo, HpcAccountUser.class));
    }

    @Override
    @Transactional
    @CacheEvict(cacheNames = {CACHE_NAME}, key = "#p0.hpcAccountUserId")
    public boolean update(@Validated HpcAccountUserUpdateQuery hpcAccountUserUpdateQuery) {
        HpcAccountUserBo hpcAccountUserBo = self.get(hpcAccountUserUpdateQuery.getHpcAccountUserId());
        if(Objects.isNull(hpcAccountUserBo)) return false;

        if (hpcAccountUserUpdateQuery.getStatus() != null) {
            boolean flag = self.frozenHpcAccount(new HpcAccountUserFrozenQuery()
                .setHpcAccountUserId(hpcAccountUserBo.getPid())
                .setHpcAccountStatus(instance(hpcAccountUserUpdateQuery.getStatus())));
            if(!flag) return false;
        }

        // 是否可以分享
        Integer canShare = hpcAccountUserUpdateQuery.getCanShare();
        if (canShare != null) {
            hpcAccountUserBo.setCanShare(canShare);
        }

        // 是否为无限算力账号
        Integer isInfinite = hpcAccountUserUpdateQuery.getIsInfinite();
        if(isInfinite != null) {
            hpcAccountUserBo.setIsInfinite(isInfinite);
        }

        return self.update(hpcAccountUserBo);
    }

    @Override
    @Transactional
    @CacheEvict(cacheNames = {CACHE_NAME}, key = "#p0.hpcAccountUserId")
    public boolean update(@Validated HpcQCloudUpdateQuery hpcAccountUserUpdateQuery) {
        String hpcAccountUserId = hpcAccountUserUpdateQuery.getHpcAccountUserId();
        String userId = hpcAccountUserUpdateQuery.getUserId();
        Date expireTime = hpcAccountUserUpdateQuery.getExpireTime();
        String slurmAccountName = hpcAccountUserUpdateQuery.getSlurmAccount();
        Double coreTime = hpcAccountUserUpdateQuery.getCoreTime();

        HpcAccountUserBo hpcAccountUserBo = self.get(hpcAccountUserId);
        AssertUtil.assertThrow("参数错误", Objects.isNull(hpcAccountUserBo));

        String hpcAccountRecordId = hpcAccountUserBo.getHpcAccountRecordId();
        HpcAccountRecordBo hpcAccountRecordBo = hpcAccountRecordService.get(hpcAccountRecordId);

        if(StrUtil.isNotBlank(userId) && !Objects.equals(userId, hpcAccountUserBo.getUserId())) {
            hpcAccountUserBo.setUserId(userId);
            hpcAccountRecordBo.setUserId(userId);
        }

        if(Objects.nonNull(expireTime)) {
            hpcAccountRecordBo.setExpireTime(DateUtil.offsetSecond(DateUtil.endOfDay(expireTime), -1));
        }

        // 更改slurm队列
        if(StrUtil.isNotBlank(slurmAccountName) && !Objects.equals(slurmAccountName, hpcAccountRecordBo.getSlurmAccount())) {
            hpcAccountRecordBo.setSlurmAccount(slurmAccountName);
            SlurmAccountBO slurmAccount = slurmService.getSlurmAccount(slurmAccountName);
            AssertUtil.assertThrow("参数错误", Objects.isNull(slurmAccount));
            // 无法保证事务
            String hpcAccountId = hpcAccountRecordBo.getHpcAccountId();
            HpcAccountBo hpcAccountBo = hpcAccountService.getById(hpcAccountId);
            String providerId = hpcAccountBo.getProviderId();
            HpcAccountProviderBo hpcAccountProviderBo = providerService.getById(providerId);
            slurmService.updateSlurmUser(hpcAccountProviderBo, hpcAccountRecordBo.getHpcAccountSnapshot(), slurmAccountName);
        }

        // 更改核时余额
        if(Objects.nonNull(coreTime)) {
            double usableCoreTime = Arith.sub(hpcAccountRecordBo.getCoreTimeBalanceTotal(), hpcAccountRecordBo.getCoreTimeBalance());
            hpcAccountRecordBo.setCoreTimeBalanceTotal(coreTime);
            hpcAccountRecordBo.setCoreTimeBalance(Arith.sub(coreTime, usableCoreTime));
        }

        this.updateById(MapperUtil.nf().map(hpcAccountUserBo, HpcAccountUser.class));
        hpcAccountRecordService.update(hpcAccountRecordBo);

        // 设置为解冻
        frozenHpcAccount(new HpcAccountUserFrozenQuery()
            .setHpcAccountUserId(hpcAccountUserId)
            .setHpcAccountStatus(NORMAL));

        return true;
    }

    @Override
    @Transactional
    @CacheEvict(cacheNames = {CACHE_NAME}, key = "#p0")
    public boolean delete(String accountUserId) {
        if (StringUtil.isBlank(accountUserId)) {
            return false;
        }

        HpcAccountUserBo accountUserBo = this.getWithRecord(accountUserId);
        if (Objects.isNull(accountUserBo)) {
            return false;
        }

        // TODO 调解绑业务
        return this.removeById(accountUserBo);
    }

    @Override
    public HpcAccountCountBo getHpcAccountCountByUserId(String userId) {

        List<HpcAccountUserBo> accountUserBos = self.getList(userId);

        int expireCount = 0;
        int count = 0;
        int subCount = 0;
        int frozenCount = 0;

        for (HpcAccountUserBo accountUserBo : accountUserBos) {
            Date expireTime = accountUserBo.getExpireTime();
            if (DateUtil.compare(expireTime, DateUtil.date()) < 0) {
                expireCount++; // 已过期
            }

            if (accountUserBo.getStatus() == SUB) {
                frozenCount++; // 冻结
            }

            if (accountUserBo.getIsMain() == MAIN) {
                count++; // 主帐号
            } else {
                subCount++; // 副帐号
            }
        }

        HpcAccountCountBo accountCountBo = new HpcAccountCountBo();

        accountCountBo.setExpireCount(expireCount);
        accountCountBo.setCount(count);
        accountCountBo.setSubCount(subCount);
        accountCountBo.setFrozenCount(frozenCount);
        accountCountBo.setTotal(accountUserBos.size());

        return accountCountBo;
    }

    @Override
    @CacheEvict(cacheNames = {CACHE_NAME}, key = "#p0", condition = "#p0 != null")
    public void unBoundHpcAccount(String hpcAccountUserId, boolean force) {
        HpcAccountUserBo accountUserBo = self.getWithRecord(hpcAccountUserId);
        AssertUtil.assertThrow("帐号不存在", Objects.isNull(accountUserBo));

        Integer isMain = accountUserBo.getIsMain();
        // 副帐号
        // 报错，不能解绑副帐号，转为提示是否删除此帐号
        AssertUtil.assertThrow("不能解绑副帐号", isMain != MAIN);

        HpcAccountPoolStatus hpcAccountStatus = hpcAccountRecordService.getHpcAccountStatus(accountUserBo.getHpcAccountId());
        AssertUtil.assertThrow("该帐号已解绑", Objects.equals(hpcAccountStatus, HpcAccountPoolStatus.FREE));
        AssertUtil.assertThrow("不能解绑此帐号，该账户未过期", !force && DateUtil.compare(accountUserBo.getExpireTime(), DateUtil.date()) > 0);

        // 账户已过期,需要手动解绑
        hpcAccountRecordService.unBoundHpcAccountRecord(accountUserBo.getHpcAccountRecordId());
    }

    @Override
    public int getFreezeCount(HpcProviderType hpcProviderType) {
        // 根据HPC类型，获取冻结数量
        return this.baseMapper.countByHpcType(hpcProviderType, DISABLED);
    }

    @Override
    public List<HpcAccountUserBo> getListByHpcAccountRecordId(String hpcAccountRecordId) {
        if (StringUtil.isBlank(hpcAccountRecordId)) return null;
        List<HpcAccountUser> list = this.list(Wrappers.<HpcAccountUser>lambdaQuery()
            .eq(HpcAccountUser::getHpcAccountRecordId, hpcAccountRecordId));
        return MapperUtil.nf().mapAsList(list, HpcAccountUserBo.class);
    }

    @Override
    public List<HpcAccountUserBo> getShareListByHpcAccountRecordId(String hpcAccountRecordId) {
        if (StringUtil.isBlank(hpcAccountRecordId)) return null;
        List<HpcAccountUser> list = this.list(Wrappers.<HpcAccountUser>lambdaQuery()
            .eq(HpcAccountUser::getHpcAccountRecordId, hpcAccountRecordId).eq(HpcAccountUser::getIsMain, SUB));
        return MapperUtil.nf().mapAsList(list, HpcAccountUserBo.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void frozenAll() {
        List<String> hpcAccountRecordIds = hpcAccountRecordService.getRecordIdsByExpire();
        if (CollectionUtils.isNotEmpty(hpcAccountRecordIds)) {
            List<HpcAccountUser> list = this.lambdaQuery()
                .select(HpcAccountUser::getStatus, HpcAccountUser::getPid)
                .in(HpcAccountUser::getHpcAccountRecordId, hpcAccountRecordIds).list();
            List<HpcAccountUser> hpcAccountUsers = new ArrayList<>();
            list.forEach(hpcAccountUser -> {
                if (hpcAccountUser.getStatus() == 1) {
                    hpcAccountUser.setStatus(0);
                    hpcAccountUsers.add(hpcAccountUser);
                }
            });
            // 提交冻结事件
            hpcAccountUsers.forEach(hpcAccountUser -> {
                String hpcAccountRecordId = hpcAccountUser.getHpcAccountRecordId();
                HpcAccountRecordBo hpcAccountRecordBo = hpcAccountRecordService.get(hpcAccountRecordId);
                if(Objects.isNull(hpcAccountRecordBo)) {
                    return;
                }
                HpcAccountBo hpcAccountBo = hpcAccountService.getById(hpcAccountRecordBo.getHpcAccountId());
                publisher.publishEvent(new HpcAccountUnAllotEvent(hpcAccountBo));
            });
            updateBatchById(hpcAccountUsers);
        }
    }

    @Override
    @Transactional
    public void deleteByRecordId(String hpcAccountRecordId) {
        List<HpcAccountUserBo> hpcAccountUserBos = self.getListByHpcAccountRecordId(hpcAccountRecordId);
        if (CollectionUtils.isEmpty(hpcAccountUserBos)) {
            return;
        }
        hpcAccountUserBos.forEach(hpcAccountUserBo -> self.delete(hpcAccountUserBo.getPid()));
    }

    @Override
    public List<HpcAccountUsersBo> findHpcAccountUsers(List<String> userId) {
        List<HpcAccountUser> list = this.lambdaQuery().in(HpcAccountUser::getUserId, userId).list();
        return MapperUtil.nf().mapAsList(list, HpcAccountUsersBo.class);
    }

    @Override
    public IPage<CustomerBO> listNeedShareCustomerByUserId(PageParam pageParam, String userId, String hpcAccountUserId, String fuzzy, String keyword) {
        if (StrUtil.isBlank(userId) || StrUtil.isBlank(hpcAccountUserId)) return new Page();

        HpcAccountUserBo accountUserBo = self.get(hpcAccountUserId);
        if (accountUserBo == null || !Objects.equals(userId, accountUserBo.getUserId())) return new Page<>();

        List<HpcAccountUserBo> hpcAccountUserBos = self.getListByHpcAccountRecordId(accountUserBo.getHpcAccountRecordId());
        if (CollectionUtil.isEmpty(hpcAccountUserBos)) return new Page<>();

        List<String> userIds = hpcAccountUserBos.stream().map(HpcAccountUserBo::getUserId).collect(Collectors.toList());
        return customerService.listCustomerByNotInUserIdAndFuzzy(pageParam == null ? new PageParam():pageParam, userIds, fuzzy, keyword);
    }

    @Override
    public IPage<CustomerBO> listShareCustomerByUserId(PageParam pageParam, String userId, String hpcAccountUserId, String fuzzy, String keyword) {
        if (StrUtil.isBlank(userId) || StrUtil.isBlank(hpcAccountUserId)) return new Page();

        HpcAccountUserBo accountUserBo = self.get(hpcAccountUserId);
        if (accountUserBo == null || !Objects.equals(userId, accountUserBo.getUserId())) return new Page<>();

        List<HpcAccountUserBo> hpcAccountUserBos = self.getShareListByHpcAccountRecordId(accountUserBo.getHpcAccountRecordId());
        if (CollectionUtil.isEmpty(hpcAccountUserBos)) return new Page<>();

        // 当前账户下，共享账户分配的用户ID集合
        List<String> userIds = hpcAccountUserBos.stream().map(HpcAccountUserBo::getUserId).collect(Collectors.toList());
        return customerService.listCustomerByInUserIdAndFuzzy(pageParam == null ? new PageParam():pageParam, userIds, fuzzy, keyword);
    }

    @Override
    public IPage<HpcSharedRecordBO> listShardHpcRecord(PageParam pageParam, String hpcAccountUserId) {
        HpcAccountUserBo hpcAccountUserBo = self.get(hpcAccountUserId);
        AssertUtil.assertThrow("参数错误,当前账号不是主账户", Objects.isNull(hpcAccountUserBo) || !Objects.equals(hpcAccountUserBo.getIsMain(), HpcAccountUserType.MAIN.value()));
        return hpcAccountRecordMapper.listShardHpcRecord(pageParam.convert(), hpcAccountUserId, null);
    }

    @Override
    public IPage<HpcSharedRecordBO> listSubShardHpcRecord(PageParam pageParam, String hpcAccountUserId, String userId) {
        return hpcAccountRecordMapper.listShardHpcRecord(pageParam.convert(), hpcAccountUserId, userId);
    }
}
